#include <config.h>
#include <render.h>
#include <stdlib.h>
#include <file.h>
#include <encoding_manager.h>
#include <fonts_manager.h>
#include <video_manager.h>
#include <convert_manager.h>
#include <picfmt_manager.h>
#include <render.h>
#include <string.h>
#include <pthread.h>
#include <time.h>


/* 菜单的区域 */
static T_Layout g_atVideoMenuIconsLayout[] = {
	{0, 0, 0, 0, "return.bmp"},
	{0, 0, 0, 0, "capture.bmp"},
    {0, 0, 0, 0, "next_page.bmp"},
	{0, 0, 0, 0, NULL},
};

static T_PageLayout g_tVideoPageMenuIconsLayout = {
	.iMaxTotalBytes = 0,
	.atLayout       = g_atVideoMenuIconsLayout,
};

static T_Layout g_tVideoPicLayout;

static pthread_t g_tVideoPlayThreadID;
static pthread_mutex_t g_tVideoPlayThreadMutex  = PTHREAD_MUTEX_INITIALIZER;  /* 互斥量 */
static pthread_mutex_t g_tVideoCaptureThreadMutex  = PTHREAD_MUTEX_INITIALIZER;  /* 互斥量 */
// static pthread_cond_t  g_tVideoPlayConVarPath = PTHREAD_COND_INITIALIZER;     // 条件变量，线程等待预加载路径
static int g_bThreadExit = 0;
static int g_bThreadCpature = 0;


static void *VideoPlayThreadFunction(void *pVoid)
{
 	int iPixelFormatOfVideo;
    int iPixelFormatOfDisp;

	PT_VideoDevice ptVideoDevice = GetVideoDevice();
    PT_VideoConvert ptVideoConvert;

    PT_PixelDatas ptVideoBufCur;
    T_PixelDatas tVideoBuf;
    T_PixelDatas tConvertBuf;
    T_PixelDatas tZoomBuf;
    
	PT_VideoMem ptVideoMemCur = GetDevVideoMem(); //GetCurVideoMem();

	int iLcdWidth, iLcdHeigt, iLcdBpp;
	int iWidth = g_tVideoPicLayout.iBotRightX - g_tVideoPicLayout.iTopLeftX + 1;
	int iHeight = g_tVideoPicLayout.iBotRightY - g_tVideoPicLayout.iTopLeftY + 1;
    int iError;
	int iCpature;
	time_t timep;
    struct tm *tmp;
	char strTimeBuf[64];
	int k;

	GetDispResolution(&iLcdWidth, &iLcdHeigt, &iLcdBpp);
	iPixelFormatOfDisp = (iLcdBpp == 16) ? V4L2_PIX_FMT_RGB565 : \
                    		(iLcdBpp == 32) ?  V4L2_PIX_FMT_RGB32 : \
                    			0;
	iPixelFormatOfVideo = GetVideoDeviceFormat(NULL);

	ptVideoConvert = GetVideoConvertForFormats(iPixelFormatOfVideo, iPixelFormatOfDisp);
    if (NULL == ptVideoConvert)
    {
        DBG_PRINTF("can not support this format convert\n");
        return NULL;
    }

    memset(&tVideoBuf, 0, sizeof(tVideoBuf));
    memset(&tConvertBuf, 0, sizeof(tConvertBuf));
    tConvertBuf.iBpp = iLcdBpp;
    memset(&tZoomBuf, 0, sizeof(tZoomBuf));
    
    while(1){
		pthread_mutex_lock(&g_tVideoPlayThreadMutex);			
		iError = g_bThreadExit;
		pthread_mutex_unlock(&g_tVideoPlayThreadMutex);
		if (iError)
			return NULL;
		
 		/* 从队列中读入摄像头数据 */
        iError = ptVideoDevice->ptOPr->GetFrame(ptVideoDevice, &tVideoBuf);
        if (iError)
        {
            DBG_PRINTF("Video GetFrame error!\n");
            break;
        }
        ptVideoBufCur = &tVideoBuf;

		/* 转换为RGB格式 */
        if (iPixelFormatOfVideo != iPixelFormatOfDisp)
        {
            iError = ptVideoConvert->Convert(iPixelFormatOfVideo, iPixelFormatOfDisp, &tVideoBuf, &tConvertBuf);
            if (iError)
            {
                DBG_PRINTF("Convert %s error!\n", ptVideoConvert->name);
                break;
            }
            ptVideoBufCur = &tConvertBuf;
        }
        
        /* 如果图像分辨率大于显示区域, 缩放 */
        if (ptVideoBufCur->iWidth > iWidth || ptVideoBufCur->iHeight > iHeight)
        {
            /* 按比例缩放 */
            k = (float)ptVideoBufCur->iHeight / ptVideoBufCur->iWidth;
            tZoomBuf.iWidth  = iWidth;
            tZoomBuf.iHeight = iWidth * k;
            if ( tZoomBuf.iHeight > iHeight)
            {
                tZoomBuf.iWidth  = iHeight / k;
                tZoomBuf.iHeight = iHeight;
            }
            tZoomBuf.iBpp        = iLcdBpp;
            tZoomBuf.iLineBytes  = tZoomBuf.iWidth * tZoomBuf.iBpp / 8;
            tZoomBuf.iTotalBytes = tZoomBuf.iLineBytes * tZoomBuf.iHeight;

            if (!tZoomBuf.aucPixelDatas)
            {
                tZoomBuf.aucPixelDatas = malloc(tZoomBuf.iTotalBytes);
            }
            
            PicZoom(ptVideoBufCur, &tZoomBuf);
            ptVideoBufCur = &tZoomBuf;
        }

        PicMerge(g_tVideoPicLayout.iTopLeftX, g_tVideoPicLayout.iTopLeftY, ptVideoBufCur, &(ptVideoMemCur->tPixelDatas));

		FlushVideoMemToDev(ptVideoMemCur);
		
		pthread_mutex_lock(&g_tVideoCaptureThreadMutex);			
		iCpature = g_bThreadCpature;
		g_bThreadCpature = 0;
		pthread_mutex_unlock(&g_tVideoCaptureThreadMutex);
		if (iCpature){
			time (&timep);
			tmp = gmtime(&timep);
			strftime(strTimeBuf, sizeof(strTimeBuf), "picture-%Y%m%d-%H%M%S.bmp", tmp);
			printf("photos name: %s\n", strTimeBuf);
			Parser("bmp")->SaveFile(ptVideoBufCur->aucPixelDatas, ptVideoBufCur->iWidth, ptVideoBufCur->iHeight, ptVideoBufCur->iBpp, strTimeBuf);
		}

        PutVideoMem(ptVideoMemCur);

		/* 重新加入空闲队列 */
        iError = ptVideoDevice->ptOPr->PutFrame(ptVideoDevice, &tVideoBuf);
        if (iError)
        {
            DBG_PRINTF("Video PutFrame error!\n");
            break;
        }
    }
	if (tConvertBuf.aucPixelDatas)
		free(tConvertBuf.aucPixelDatas);
	if (tZoomBuf.aucPixelDatas)
		free(tZoomBuf.aucPixelDatas);
	return NULL;
}



/**********************************************************************
 * 函数名称： CalcVideoPageMenusLayout
 * 功能描述： 计算页面中各图标座标值
 * 输入参数： 无
 * 输出参数： ptPageLayout - 内含各图标的左上角/右下角座标值
 * 返 回 值： 无
 * 修改日期        版本号     修改人	      修改内容
 * -----------------------------------------------
 * 2013/02/08	     V1.0	  韦东山	      创建
 ***********************************************************************/
static void  CalcVideoPageMenusLayout(PT_PageLayout ptPageLayout)
{
	int iWidth;
	int iHeight;
	int iXres, iYres, iBpp;
	int iTmpTotalBytes;
	PT_Layout atLayout;
	int i;
    int iCount = 0; // 按钮个数

    iCount = sizeof(g_atVideoMenuIconsLayout) / sizeof(g_atVideoMenuIconsLayout[0]) - 1;

	atLayout = ptPageLayout->atLayout;
	GetDispResolution(&iXres, &iYres, &iBpp);
	ptPageLayout->iBpp = iBpp;

	if (iXres < iYres)
	{			 
		/*	 iXres/6
		 *	  --------------------------------------------------------------
		 *	   return	zoomout	zoomin  pre_pic next_pic continue_mod_small
		 *
		 *
		 *
		 *
		 *
		 *
		 *	  --------------------------------------------------------------
		 */
		 
		iWidth  = iXres / iCount;
		iHeight = iWidth;

		/* return图标 */
		atLayout[0].iTopLeftY  = 0;
		atLayout[0].iBotRightY = atLayout[0].iTopLeftY + iHeight - 1;
		atLayout[0].iTopLeftX  = 0;
		atLayout[0].iBotRightX = atLayout[0].iTopLeftX + iWidth - 1;

        /* 其他图标 */
        for (i = 1; i < iCount; i++)
        {
    		atLayout[i].iTopLeftY  = 0;
    		atLayout[i].iBotRightY = atLayout[i].iTopLeftY + iHeight - 1;
    		atLayout[i].iTopLeftX  = atLayout[i-1].iBotRightX + 1;
    		atLayout[i].iBotRightX = atLayout[i].iTopLeftX + iWidth - 1;
        }

	}
	else
	{
		/*	 iYres/6
		 *	  ----------------------------------
		 *	   up		  
		 *
		 *    zoomout	    
		 *
		 *    zoomin
		 *  
		 *    pre_pic
		 *
		 *    next_pic
		 *
		 *    continue_mod_small
		 *
		 *	  ----------------------------------
		 */
		 
		iHeight  = iYres / iCount;
		iWidth = iHeight;

		/* return图标 */
		atLayout[0].iTopLeftY  = 0;
		atLayout[0].iBotRightY = atLayout[0].iTopLeftY + iHeight - 1;
		atLayout[0].iTopLeftX  = 0;
		atLayout[0].iBotRightX = atLayout[0].iTopLeftX + iWidth - 1;
		
        /* 其他5个图标 */
        for (i = 1; i < iCount; i++)
        {
    		atLayout[i].iTopLeftY  = atLayout[i-1].iBotRightY+ 1;
    		atLayout[i].iBotRightY = atLayout[i].iTopLeftY + iHeight - 1;
    		atLayout[i].iTopLeftX  = 0;
    		atLayout[i].iBotRightX = atLayout[i].iTopLeftX + iWidth - 1;
        }		
	}

	i = 0;
	while (atLayout[i].strIconName)
	{
		iTmpTotalBytes = (atLayout[i].iBotRightX - atLayout[i].iTopLeftX + 1) * (atLayout[i].iBotRightY - atLayout[i].iTopLeftY + 1) * iBpp / 8;
		if (ptPageLayout->iMaxTotalBytes < iTmpTotalBytes)
		{
			ptPageLayout->iMaxTotalBytes = iTmpTotalBytes;
		}
		i++;
	}
}


/**********************************************************************
 * 函数名称： CalcVideoPagePicLayout
 * 功能描述： 计算"Video页面"中"图片的显示区域"
 * 输入参数： 无
 * 输出参数： 无
 * 返 回 值： 无
 * 修改日期        版本号     修改人	      修改内容
 * -----------------------------------------------
 * 2013/02/08	     V1.0	  韦东山	      创建
 ***********************************************************************/
static void CalcVideoPagePicLayout(void)
{
	int iXres, iYres, iBpp;
	int iTopLeftX, iTopLeftY;
	int iBotRightX, iBotRightY;
	
	GetDispResolution(&iXres, &iYres, &iBpp);

	if (iXres < iYres)
	{
		/*	 iXres/6
		 *	  --------------------------------------------------------------
		 *	   return	zoomout	zoomin  pre_pic next_pic continue_mod_small  (图标)
		 *	  --------------------------------------------------------------
		 *
		 *                              图片
		 *
		 *
		 *	  --------------------------------------------------------------
		 */
		iTopLeftX  = 0;
		iBotRightX = iXres - 1;
		iTopLeftY  = g_atVideoMenuIconsLayout[0].iBotRightY + 1;
		iBotRightY = iYres - 1;
	}
	else
	{
		/*	 iYres/6
		 *	  --------------------------------------------------------------
		 *	   up		         |
		 *                       |
		 *    zoomout	         |
		 *                       |
		 *    zoomin             |
		 *                       |
		 *    pre_pic            |                 图片
		 *                       |
		 *    next_pic           |
		 *                       |
		 *    continue_mod_small | 
		 *                       |
		 *	  --------------------------------------------------------------
		 */
		iTopLeftX  = g_atVideoMenuIconsLayout[0].iBotRightX + 1;
		iBotRightX = iXres - 1;
		iTopLeftY  = 0;
		iBotRightY = iYres - 1;
	}

    g_tVideoPicLayout.iTopLeftX   = iTopLeftX;
    g_tVideoPicLayout.iTopLeftY   = iTopLeftY;
    g_tVideoPicLayout.iBotRightX  = iBotRightX;
    g_tVideoPicLayout.iBotRightY  = iBotRightY;
    g_tVideoPicLayout.strIconName = NULL;
}


/**********************************************************************
 * 函数名称： ShowPicInVideoPage
 * 功能描述： 在"Video页面"中显示图片
 * 输入参数： ptVideoMem  - 在这个VideoMem中显示
 * 输出参数： 无
 * 返 回 值： 0      - 成功
 *            其他值 - 失败
 * 修改日期        版本号     修改人	      修改内容
 * -----------------------------------------------
 * 2013/02/08	     V1.0	  韦东山	      创建
 ***********************************************************************/
static int ShowPicInVideoPage(PT_VideoMem ptVideoMem)
{
	// 清屏
    ClearRectangleInVideoMem(g_tVideoPicLayout.iTopLeftX, g_tVideoPicLayout.iTopLeftY, \
                                        g_tVideoPicLayout.iBotRightX, g_tVideoPicLayout.iBotRightY, \
                                        ptVideoMem, COLOR_BACKGROUND);
    return 0;
}


/**********************************************************************
 * 函数名称： ShowVideoPage
 * 功能描述： 显示"Video页面": 除了显示菜单图标外,还会显示图片
 * 输入参数： ptPageLayout - 内含多个图标的文件名和显示区域
 *            strFileName  - 要显示的图片
 * 输出参数： 无
 * 返 回 值： 无
 * 修改日期        版本号     修改人	      修改内容
 * -----------------------------------------------
 * 2013/02/08	     V1.0	  韦东山	      创建
 ***********************************************************************/
static void ShowVideoPage(PT_PageLayout ptPageLayout)
{
	PT_VideoMem ptVideoMem;
	int iError;

	PT_Layout atLayout = ptPageLayout->atLayout;
		
	/* 1. 获得显存 */
	ptVideoMem = GetVideoMem(ID("video"), 1);
	if (ptVideoMem == NULL)
	{
		DBG_PRINTF("can't get video mem for Video page!\n");
		return;
	}

	/* 2. 描画数据 */

	/* 如果还没有计算过各图标的坐标 */
	if (atLayout[0].iTopLeftX == 0)
	{
		CalcVideoPageMenusLayout(ptPageLayout);
        CalcVideoPagePicLayout();
	}
    /* 在videomem上生成图标 */
	iError = GeneratePage(ptPageLayout, ptVideoMem);
    iError = ShowPicInVideoPage(ptVideoMem);
    if (iError)
    {
        PutVideoMem(ptVideoMem);
        return;
    }
    
	/* 3. 刷到设备上去 */
	FlushVideoMemToDev(ptVideoMem);

	/* 4. 解放显存 */
	PutVideoMem(ptVideoMem);

    /* 刷新显示鼠标 */
    int iX, iY;
    GetMousePos(&iX, &iY);
    FreeMouseBox();
    SwitchRegionInDev(iX, iY, GetMouseIconPixelDatas(), GetMouseBox());
}


/**********************************************************************
 * 函数名称： VideoPageGetInputEvent
 * 功能描述： 为"Video页面"获得输入数据,判断输入事件位于哪一个图标上
 * 输入参数： ptPageLayout - 内含多个图标的显示区域
 * 输出参数： ptInputEvent - 内含得到的输入数据
 * 返 回 值： -1     - 输入数据不位于任何一个图标之上
 *            其他值 - 输入数据所落在的图标(PageLayout->atLayout数组的哪一项)
 * 修改日期        版本号     修改人	      修改内容
 * -----------------------------------------------
 * 2013/02/08	     V1.0	  韦东山	      创建
 ***********************************************************************/
static int VideoPageGetInputEvent(PT_PageLayout ptPageLayout, PT_InputEvent ptInputEvent)
{	
	return GenericGetInputEvent(ptPageLayout, ptInputEvent);
}


/**********************************************************************
 * 函数名称： VideoPageRun
 * 功能描述： "Video页面"的运行函数: 显示菜单图标,显示图片,根据用户操作作出反应(比如缩放/移动图片等)
 * 输入参数： ptParentPageParams - 内含上一个页面(父页面)的参数
 *                                 ptParentPageParams->iPageID等于ID("main")时,显示"浏览页面";否则显示图片
 * 输出参数： 无
 * 返 回 值： 无
 * 修改日期        版本号     修改人	      修改内容
 * -----------------------------------------------
 * 2013/02/08	     V1.0	  韦东山	      创建
 ***********************************************************************/
static void VideoPageRun(PT_PageParams ptParentPageParams)
{
	T_InputEvent tInputEvent;

	int bButtonPressed = 0;
	int iIndexPressed = -1;
    int iIndex;
    int iError;

    PT_VideoMem ptCurVideoMem;
	PT_VideoDevice ptVideoDevice = GetVideoDevice();
	
	g_bThreadExit = 0;
	g_bThreadCpature = 0;
	
	/* 启动摄像头设备 */
    iError = ptVideoDevice->ptOPr->StartDevice(ptVideoDevice);
    if (iError)
    {
        DBG_PRINTF("Video StartDevice error!\n");
        return ;
    }

	/* 启动线程 */
    pthread_create(&g_tVideoPlayThreadID, NULL, VideoPlayThreadFunction, NULL);

    (void)iError;
    /* 显示菜单和文本文件 */
    ShowVideoPage(&g_tVideoPageMenuIconsLayout);
    ptCurVideoMem = GetCurVideoMem();

    while (1)
    {
        /* 先确定是否触摸了菜单图标 */
        iIndex = VideoPageGetInputEvent(&g_tVideoPageMenuIconsLayout, &tInputEvent);
		
		/* 如果是松开 */
        if (tInputEvent.iPressure == 0)
        {			
            if (bButtonPressed)
            {
                /* 曾经有按钮被按下 */
                ReleaseButton(&g_atVideoMenuIconsLayout[iIndexPressed]);
                bButtonPressed = 0;

                if (iIndexPressed == iIndex) /* 按下和松开都是同一个按钮 */
                {
                    SwitchRegionInDev(tInputEvent.iX, tInputEvent.iY, GetMouseIconPixelDatas(), GetMouseBox());
                    switch (iIndexPressed)
                    {
                        case 0: /* 返回按钮 */
                        {
							/* 终止线程 */
							pthread_mutex_lock(&g_tVideoPlayThreadMutex);
							g_bThreadExit = 1;
							pthread_mutex_unlock(&g_tVideoPlayThreadMutex);
							pthread_join(g_tVideoPlayThreadID, NULL);
							/* 停止摄像头设备 */
							iError = ptVideoDevice->ptOPr->StopDevice(ptVideoDevice);
							if (iError)
							{
								DBG_PRINTF("Video StopDevice  error!\n");
							}
                            return;
                        }
                        case 1: /* "拍照"按钮 */
                        {
							DBG_PRINTF("点击拍照按钮\n");
							// 外部无法直接获取显示区域，改为在线程内部转换
							pthread_mutex_lock(&g_tVideoCaptureThreadMutex);
							g_bThreadCpature = 1;
							pthread_mutex_unlock(&g_tVideoCaptureThreadMutex);
							// while(g_bThreadCpature);
                            break;
                        }
                        case 2: /* "下一张"按钮 */
                        {
                            break;
                        }
                        default:
                        {
                            break;
                        }
                    }
                }
                
                iIndexPressed = -1;
            }
        }
        else if (tInputEvent.iPressure > 0)/* 按下状态 */
        {
            /* 点击的是菜单按钮 */
            if (iIndex != -1)
            {
                if (!bButtonPressed)
                {
                    /* 未曾按下按钮 */
                    bButtonPressed = 1;
                    iIndexPressed = iIndex;
                    PressButton(&g_atVideoMenuIconsLayout[iIndexPressed]);
                    SwitchRegionInDev(tInputEvent.iX, tInputEvent.iY, GetMouseIconPixelDatas(), GetMouseBox());
                }
            }
			// else  /* 点击的是图片显示区域, 滑动图片 */
			// {
			// 	/* 如果没有按钮被按下 */
			// 	if (!bButtonPressed)
			// 	{
            //         tPreInputEvent = tInputEvent;
			// 	}
			// }
        }       
    }
}

static T_PageAction g_tVideoPageAction = {
	.name          = "video",
	.Run           = VideoPageRun,
};


/**********************************************************************
 * 函数名称： VideoPageInit
 * 功能描述： 注册"Video页面"
 * 输入参数： 无
 * 输出参数： 无
 * 返 回 值： 0 - 成功, 其他值 - 失败
 * 修改日期        版本号     修改人	      修改内容
 * -----------------------------------------------
 * 2013/02/08	     V1.0	  韦东山	      创建
 ***********************************************************************/
int VideoPageInit(void)
{
	return RegisterPageAction(&g_tVideoPageAction);
}

